<?php

namespace services\api;

use api\modules\mini\forms\LoginForm as MiniLoginForm;
use api\modules\v1\forms\LoginForm;
use common\components\Service;
use common\helpers\CommonHelper;
use common\models\log\LogLogin;
use common\models\api\AccessToken;
use common\models\member\Member;
use common\models\spoker\Spoker;
use common\models\user\User;
use services\log\LogLoginService;
use services\member\MemberService;
use services\user\UserService;
use Yii;
use yii\db\ActiveRecord;

/**
 * Class AccessTokenService
 * @package services\api
 */
class AccessTokenService extends Service
{
    /**
     * 是否加入缓存
     *
     * @var bool
     */
    public $cache = false;

    /**
     * 缓存过期时间
     *
     * @var int
     */
    public $timeout;

    /**
     * 登陆获取token
     * @param LoginForm $model
     * @return array|mixed
     */
    public function login(LoginForm $model)
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            $member = $model->getMember();

            // 1.生成token信息
            $accessToken = $model->getAccessToken();
            if (empty($accessToken)) {
                $accessToken = new AccessToken();
                $accessToken->group = $model->group;
                $accessToken->status = AccessToken::STATUS_ENABLE;
            }
            $accessToken->member_id = $member->id;
            // 是否重新生成token
            $isRefreshToken = true;
            if ($accessToken->access_token && $accessToken->status == AccessToken::STATUS_ENABLE && Yii::$app->params['user.accessTokenIsRefresh'] === false) {
                $timestamp = (int)substr($accessToken->access_token, strrpos($accessToken->access_token, '_') + 1);
                $expire = Yii::$app->params['user.accessTokenExpire'];

                // 过期重新生成，未过期不生成
                $isRefreshToken = $timestamp + $expire <= time() ? true : false;
            }
            if ($isRefreshToken) {
                // 超过有效期,重新生成token
                $accessToken->access_token && Yii::$app->cache->delete($this->getCacheKey($accessToken->access_token));
                $accessToken->refresh_token = Yii::$app->security->generateRandomString() . '_' . time();
                $accessToken->access_token = Yii::$app->security->generateRandomString() . '_' . time();
                $accessToken->status = AccessToken::STATUS_ENABLE;
            }
            $accessToken->saveAndCheckResult();

            if ($member->super_type != Member::SUPER_TYPE_SUPER_ADMIN) {
                // 2.记录访问次数
                MemberService::lastLogin($member);

                // 3.新增登陆日志
                LogLoginService::loginLog($member, $model->group, LogLogin::LOGIN_TYPE_IN);
            }

            $transaction->commit();

            return [
                'access_token' => $accessToken->access_token,
                'info' => [
                    'member_id' => $member->id,
//                    'username' => $member->username,
                    'realname' => $member->realname,
                    'mobile' => $member->mobile,
                    'super_type' => $member->super_type,
                ],
            ];
        } catch (\Exception $e) {
            $transaction->rollBack();

            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * 小程序登陆获取token
     * @param MiniLoginForm $model
     * @return array|mixed
     */
    public function minilogin(MiniLoginForm $model, User $user)
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.生成token信息
            $accessToken = AccessToken::findOne([
                'member_id' => $user->id,
                'group' => $model->group
            ]);
            if (empty($accessToken)) {
                $accessToken = new AccessToken();
                $accessToken->group = $model->group;
                $accessToken->status = AccessToken::STATUS_ENABLE;
            }
            $accessToken->member_id = $user->id;
            // 是否重新生成token
            $isRefreshToken = true;
            if ($accessToken->access_token && $accessToken->status == AccessToken::STATUS_ENABLE && Yii::$app->params['c.user.accessTokenIsRefresh'] === false) {
                $timestamp = (int)substr($accessToken->access_token, strrpos($accessToken->access_token, '_') + 1);
                $expire = Yii::$app->params['c.user.accessTokenExpire'];

                // 过期重新生成，未过期不生成
                $isRefreshToken = $timestamp + $expire <= time() ? true : false;
            }
            if ($isRefreshToken) {
                // 超过有效期,重新生成token
                $accessToken->access_token && Yii::$app->cache->delete($this->getCacheKey($accessToken->access_token));
                $accessToken->refresh_token = Yii::$app->security->generateRandomString() . '_' . time();
                $accessToken->access_token = Yii::$app->security->generateRandomString() . '_' . time();
                $accessToken->status = AccessToken::STATUS_ENABLE;
            }
            $accessToken->saveAndCheckResult();
            // 2.记录访问次数
//            MemberService::lastLogin($member);
            // 3.新增登陆日志
//            LogLoginService::loginLog($member, $model->group, LogLogin::LOGIN_TYPE_IN);

            $transaction->commit();

            return [
                'access_token' => $accessToken->access_token,
                'info' => [
                    'user_id' => $user->id,
                ],
            ];
        } catch (\Exception $e) {
            $transaction->rollBack();

            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * 登陆
     * @param MiniLoginForm $model
     * @return array|mixed
     * @throws \Exception
     */
    public function getMiniAccessToken(MiniLoginForm $model)
    {
        $user = $model->getUser();
        if (empty($user)) {
            $user = UserService::createUser($model->openid);
        }

        return $this->minilogin($model, $user);
    }

    /**
     * 退出登陆
     * @param $access_token
     */
    public function logout()
    {
        try {
            $access_token = Yii::$app->user->identity->access_token;
            $this->cache === true && Yii::$app->cache->delete($this->getCacheKey($access_token));

            if ($model = $this->getTokenByAccessToken($access_token)) {
                $model->status = AccessToken::STATUS_INVALID;
                $model->saveAndCheckResult();
            }
            return ['id' => $model->member_id];
        } catch (\Exception $e) {
            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * @param $token
     * @return array|mixed|null|ActiveRecord
     */
    public function getTokenToCache($token)
    {
        if ($this->cache == false) {
            return $this->getTokenByAccessToken($token);
        }

        $key = $this->getCacheKey($token);
        if (!($model = Yii::$app->cache->get($key))) {
            $model = $this->getTokenByAccessToken($token);
            Yii::$app->cache->set($key, $model, $this->timeout);
        }

        return $model;
    }

    /**
     * 获取token
     * @param $token
     * @return array|null|AccessToken
     */
    public function getTokenByAccessToken($token): ?AccessToken
    {
        return AccessToken::find()
            ->where([
                'access_token' => $token,
                'status' => AccessToken::STATUS_ENABLE
            ])
            ->one();
    }

    /**
     * @param $access_token
     * @return string
     */
    protected function getCacheKey($access_token)
    {
        return 'api:access-token:' . $access_token;
    }

    /**
     * 清空用户token
     * @param int|array $memberIds
     * @return void
     */
    public static function clearMemeberToken($memberIds)
    {
        AccessToken::updateAll(['status' => AccessToken::STATUS_DELETE], ['member_id' => $memberIds, 'group' => AccessToken::GROUP_PC]);
    }
}
